package com.tengju.user.application.archives;

import com.tengju.user.application.archives.dto.BatchStarAddDTO;
import com.tengju.user.application.archives.dto.BatchStarAuditUpdateDTO;
import com.tengju.user.application.shared.ApplicationException;
import com.tengju.user.application.shared.ApplicationExceptionCode;
import com.tengju.user.application.sms.SmsBizService;
import com.tengju.user.domain.model.sign.*;
import com.tengju.user.domain.model.survey.SurveyContent;
import com.tengju.user.domain.model.survey.SurveyRepotiory;
import com.tengju.user.domain.model.user.*;
import com.tengju.user.domain.service.RemoteUserService;
import com.tengju.user.domain.service.UserDocService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StarSignService {

    @Autowired
    StarSignInfoRepository starSignInfoRepository;

    @Autowired
    StarContractRepository starContractRepository;

    @Autowired
    UserInfoRepository userInfoRepository;

    @Autowired
    StarChangeRecordRepository starChangeRecordRepository;

    @Autowired
    SurveyRepotiory surveyRepotiory;

    @Autowired
    StarManageService starManageService;

    @Autowired
    StarLimitRepository starLimitRepository;

    @Autowired
    SmsBizService smsBizService;

    @Autowired
    UserDocService userDocService;

    @Autowired
    RemoteUserService remoteUserService;

    @Value("${star.sign.renew.forward.month}")
    Integer renewForwardMonth;

    @Value("${star.sign.contract.valid.day}")
    Integer contractValidDay;

    @Value("${star.sign.expire.day}")
    Integer signExpireDay;

    @Value("${star.survey.id}")
    Long starSurveyId;

    @Value("${star.auto.invite.flag}")
    boolean starAutoInviteFlag;

    @Value("${star.auto.change.flag}")
    boolean starAutoChangeFlag;

    @Value("${star.auto.change.operate.flag}")
    boolean starAutoChangeOperateFlag;


    /**
     * 批量发送邀约信息
     *
     * @param batchStarAddDTO 用户列表
     * @param staff      操作人
     * @return boolean 成功失败
     */
    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public Boolean batchInviteStar(BatchStarAddDTO batchStarAddDTO, StarSignTriggerTypeEnum triggerTypeEnum, Staff staff) {
        List<Long> idCodeList = batchStarAddDTO.getIdCodeList();
        for (Long idCode : idCodeList) {
            inviteStarSign(new UserIdCode(idCode),
                    triggerTypeEnum,
                    batchStarAddDTO.getTargetStarRole(),
                    batchStarAddDTO.getTargetStarLevel(),
                    staff
            );
        }
        return true;
    }

    public Boolean batchAuditStar(BatchStarAuditUpdateDTO batchStarAuditUpdateDTO, Staff staff) {
        List<Long> idList = batchStarAuditUpdateDTO.getIdList();
        List<StarSignInfo> starSignInfoList = starSignInfoRepository.batchGetByIds(idList);
        for (StarSignInfo starSignInfo : starSignInfoList) {
            Integer curStep = starSignInfo.getStep();
            starSignInfo.updateAudit(batchStarAuditUpdateDTO.getAuditDesc(),
                    batchStarAuditUpdateDTO.getAuditStatus(),
                    staff);
            starSignInfoRepository.singleCasUpdate(starSignInfo, curStep);
            UserInfo userInfo = remoteUserService.getByIdCode(starSignInfo.getIdCode());

            //发送短信
            if (StarAuditStatEnum.isPass(batchStarAuditUpdateDTO.getAuditStatus())) {
                smsBizService.sendSignAuditSuccessMsg(userInfo.getWholePhoneNumber());
            } else {
                smsBizService.sendSignAuditFailMsg(userInfo.getWholePhoneNumber());
            }
        }
        return true;
    }

    public Boolean batchStopSign(List<UserIdCode> targetIdCodes, Staff staff) {
        List<StarSignInfo> starSignInfoList = starSignInfoRepository.batchGetByIdCodes(targetIdCodes);
        for (StarSignInfo starSignInfo : starSignInfoList) {
            doStopSign(starSignInfo, staff);
        }
        return true;
    }


    public void doStopSign(StarSignInfo starSignInfo, Staff staff) {
        if (starSignInfo == null) {
            return;
        }
        Integer curStep = starSignInfo.getStep();
        starSignInfo.stopSign(staff);
        starSignInfoRepository.singleCasUpdate(starSignInfo, curStep);
    }


    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public void inviteStarSign(UserIdCode idCode,
                               StarSignTriggerTypeEnum triggerTypeEnum,
                               Integer targetStarRole,
                               Integer targetStarLevel,
                               Staff staff) {
        StarSignInfo existStarSignInfo = starSignInfoRepository.getByIdCode(idCode);
        if (existStarSignInfo != null) {
            log.info("用户已经在签约流程中，不发送邀请，idCode:{}", idCode);
            throw new StarSignException(String.format("用户:%s 邀请发送失败，用户已经在签约流程中", idCode));
        }
        UserInfo userInfo = userDocService.searchUserByIdCodeOrMobile(idCode, null);
        //当前等级大于邀请等级的不做处理
        if (userInfo.getStarLevel() >= targetStarLevel) {
            log.warn("当前等级大于邀请等级的不做处理,idCode:{},curStarLevel:{},targetStarLevel:{}", idCode, userInfo.getStarLevel(), targetStarLevel);
            throw new StarSignException(String.format("用户:%s 邀请发送失败，当前等级大于邀请等级", idCode));
        }
        StarContractInfo existStarContractInfo = starContractRepository.getByIdCodeAndType(idCode, targetStarRole);
        if (existStarContractInfo != null && !existStarContractInfo.isRenewContract(renewForwardMonth)) {
            log.warn("当前星级身份还在合同期内，不需要重新签约,idCode:{}", idCode);
            throw new StarSignException(String.format("用户:%s 邀请发送失败，当前星级身份还在合同期内，不需要重新签约", idCode));
        }

        StarSignInfo starSignInfo = new StarSignInfo(
                idCode,
                userInfo.getStarRole(),
                userInfo.getStarLevel(),
                targetStarRole,
                targetStarLevel,
                triggerTypeEnum.getCode(),
                LocalDateTime.now(),
                staff
        );
        starSignInfo.expireDate(signExpireDay);
        //先调查问卷查询
        Boolean isSubmitByIdCodeSurveyId = surveyRepotiory.isSubmitByIdCodeSurveyId(idCode, starSurveyId);
        if (Boolean.TRUE.equals(isSubmitByIdCodeSurveyId)) {
            starSignInfo.submitSurvey();

            //后身份认证查询
//            IdentityType identityType = starSignInfoRepository.getIdentityType(idCode);
//            Integer accountType = identityType == null ? null : identityType.getAccountType();
//            if (StarLevelEnum.isMatchAccountType(targetStarLevel, accountType)) {
//                int indicatorRequireStat = 0;
//                starSignInfo.startAudit(accountType, indicatorRequireStat);
//            }
        }

        starSignInfoRepository.insert(starSignInfo);
        StarLevelEnum starLevelEnum = StarLevelEnum.parseByCode(starSignInfo.getStarLevel());

        //发送短信
        smsBizService.sendSmsSignInvite(userInfo.getWholePhoneNumber(), starLevelEnum);
    }


    public StarSignInfo addAuditData(StarAccountEvent starAccountEvent) {
        UserIdCode idCode = starAccountEvent.getIdCode();
        Integer accountType = starAccountEvent.getAccountType();
        StarSignInfo starSignInfo = starSignInfoRepository.getByIdCode(idCode);
        if (starSignInfo == null) {
            log.warn("星级签约数据已经过期或终止，不做处理，idCode:{}", idCode);
            throw new StarSignException(String.format("用户:%s 星级签约数据已经过期或终止，审核数据生成失败", idCode));
        }
        Integer curStep = starSignInfo.getStep();
        if (!StarLevelEnum.isMatchAccountType(starSignInfo.getStarLevel(), starAccountEvent.getAccountType())) {
            log.warn("星级签约类别和支付认证身份不匹配，不做处理，idCode:{}，targetLevel:{},accountType:{}", idCode, starSignInfo.getStarLevel(), starAccountEvent.getAccountType());
            throw new StarSignException(String.format("用户:%s 星级签约类别和支付认证身份不匹配，审核数据生成失败,targetLevel:%s,accountType:%s", idCode, starSignInfo.getStarLevel(), starAccountEvent.getAccountType()));
        }
        int indicatorRequireStat = 0;
        starSignInfo.startAudit(accountType, indicatorRequireStat);
        starSignInfoRepository.singleCasUpdate(starSignInfo, curStep);
        return starSignInfo;
    }

    public void finishSign(UserIdCode idCode) {
        StarSignInfo starSignInfo = starSignInfoRepository.getByIdCode(idCode);
        if (starSignInfo == null) {
            return;
        }
        Integer curStep = starSignInfo.getStep();
        starSignInfo.finishSign();
        starSignInfoRepository.singleCasUpdate(starSignInfo, curStep);
    }


    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public boolean addStarData(StarContractEvent starSignEvent) {
        UserIdCode idCode = starSignEvent.getIdCode();
        StarSignInfo starSignInfo = starSignInfoRepository.getByIdCode(idCode);
        if (starSignInfo == null) {
            log.warn("星级签约数据已经过期或终止，不做处理，idCode:{}", idCode);
            return false;
        }
        Integer curStep = starSignInfo.getStep();
        Integer targetStarRole = starSignInfo.getStarRole();
        Integer targetStarLevel = starSignInfo.getStarLevel();

        //判断是否三个月续签
        //是否重复数据，已经有签约数据了
        LocalDateTime signDate = starSignEvent.getContractSignDate();
        StarContractInfo existStarContractInfo = starContractRepository.getByIdCodeAndType(idCode, targetStarRole);
        LocalDateTime expireDate = signDate.plusDays(contractValidDay)
                .withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
        if (existStarContractInfo != null) {
            LocalDateTime contractExpireDate = existStarContractInfo.getContractExpireDate();
            if (!existStarContractInfo.isRenewContract(renewForwardMonth)) {
                log.warn("星级签约时间不在续签范围内，不做处理，idCode:{}，signDate:{}", idCode, signDate);
                return false;
            }
            expireDate = contractExpireDate.minusDays(contractValidDay)
                    .withHour(0)
                    .withMinute(0)
                    .withSecond(0)
                    .withNano(0);
            //失效原本的合同数据
            existStarContractInfo.invalid();
            starContractRepository.update(existStarContractInfo);
        }
        StarContractInfo newStarContractInfo = new StarContractInfo(
                idCode,
                targetStarRole,
                starSignEvent.getContractId(),
                StarContractStatus.VALID.getStatus(),
                signDate,
                expireDate
        );
        //插入新的合同数据
        starContractRepository.insert(newStarContractInfo);
        //插入或更新星级数据
        UserInfo userInfo = userDocService.searchUserByIdCodeOrMobile(idCode, null);
        starManageService.tryUpdateStar(userInfo, targetStarRole, targetStarLevel, StarChangeTypeEnum.AUTO, Staff.getAdminStaff(),true);
        //邀请数据更新签约完成状态
        starSignInfo.passSign();
        starSignInfoRepository.singleCasUpdate(starSignInfo, curStep);
        StarLevelEnum starLevelEnum = StarLevelEnum.parseByCode(starSignInfo.getStarLevel());

        //发送短信
        smsBizService.sendSmsSignSuccess(userInfo.getWholePhoneNumber(), starLevelEnum, expireDate);
        return true;
    }

    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public void inviteOrChangeStar(StarChangeNoticeRecord starChangeNoticeRecord) {
        UserIdCode idCode = starChangeNoticeRecord.getIdCode();
        UserInfo userInfo = userDocService.searchUserByIdCodeOrMobile(idCode, null);
        if (userInfo == null) {
            log.info("用户信息查不到，idCode:{},noticeDate:{}", idCode, starChangeNoticeRecord.getNoticeDate());
            return;
        }
        //黑名单判断
        List<StarLimitInfo> starLimitInfos = starLimitRepository.listStarLimit(idCode);
        long limitNum = starLimitInfos.stream()
                .filter(v -> v.getLimitHighestStarLevel() < starChangeNoticeRecord.getTargetStarLevel())
                .count();
        if (limitNum > 0) {
            log.info("用户存在黑名单等级限制，不自动处理，idCode:{}", idCode);
            return;
        }
        StarRoleEnum beforeStarRoleEnum = StarRoleEnum.parseByRole(userInfo.getStarRole());
        StarRoleEnum targetStarRoleEnum = StarRoleEnum.parseByRole(starChangeNoticeRecord.getTargetStarRole());
        // 入星判断直接发送邀请
        if (StarRoleEnum.NONE.equals(beforeStarRoleEnum)) {
            if (!StarRoleEnum.SERVICE_PROVIDER.equals(targetStarRoleEnum)) {
                log.info("运营商入星不自动发送邀请，idCode:{},noticeDate:{}", idCode, starChangeNoticeRecord.getNoticeDate());
                return;
            }
            if (starAutoInviteFlag) {
                inviteStarSign(
                        starChangeNoticeRecord.getIdCode(),
                        StarSignTriggerTypeEnum.SYS_AUTO,
                        starChangeNoticeRecord.getTargetStarRole(),
                        starChangeNoticeRecord.getTargetStarLevel(),
                        Staff.getAdminStaff());
            }
            return;
        }
        if (beforeStarRoleEnum != targetStarRoleEnum) {
            log.warn("不同星级类别的变更目前不支持，idCode:{}", idCode);
            return;
        }
        Integer curStarLevel = userInfo.getStarLevel();
        Integer targetStarLevel = starChangeNoticeRecord.getTargetStarLevel();
        if (!StarLevelEnum.isRise(curStarLevel, targetStarLevel)) {
            log.warn("目前只支持自动升星操作，idCode:{}，curStarLevel:{},targetStarLevel:{}", idCode, curStarLevel, targetStarLevel);
            return;
        }
        //星级变更
        if (starAutoChangeFlag) {
            //运营商等级不做自动变更
            if (!starAutoChangeOperateFlag && targetStarRoleEnum == StarRoleEnum.OPERATOR) {
                log.info("运营商等级不做自动变更，idCode:{}", idCode);
                return;
            }
            starManageService.tryUpdateStar(
                    userInfo,
                    starChangeNoticeRecord.getTargetStarRole(),
                    starChangeNoticeRecord.getTargetStarLevel(),
                    StarChangeTypeEnum.AUTO,
                    Staff.getAdminStaff(),
                    false
            );
        }
    }


    @Transactional(value = "dealerTransactionManager", rollbackFor = Exception.class)
    public void submitSurveyContent(SurveyContent surveyContent) {
        UserIdCode idCode = surveyContent.getIdCode();
        StarSignInfo starSignInfo = starSignInfoRepository.getByIdCode(idCode);
        if (starSignInfo == null) {
            return;
        }
        surveyRepotiory.saveSurveyContent(surveyContent);
        Integer curStep = starSignInfo.getStep();
        starSignInfo.submitSurvey();
        starSignInfoRepository.singleCasUpdate(starSignInfo, curStep);
    }

    public void passExam(UserIdCode idCode) {
        StarSignInfo starSignInfo = starSignInfoRepository.getByIdCode(idCode);
        if (starSignInfo == null) {
            log.warn("星级签约数据已经过期或终止，不做处理，idCode:{}", idCode);
            return;
        }
        Integer curStep = starSignInfo.getStep();
        starSignInfo.passExam();
        starSignInfoRepository.singleCasUpdate(starSignInfo, curStep);
    }

    public List<UserIdCode> queryIdCodeBySignStatus(List<UserIdCode> idCodes,StarSignStatus signStatus) {
        List<StarSignInfo> starSignInfos = starSignInfoRepository.batchGetByIdCodesSignStatus(idCodes, signStatus);
        if (CollectionUtils.isEmpty(starSignInfos)) {
            return null;
        }
        return starSignInfos.stream()
                .map(StarSignInfo::getIdCode).collect(Collectors.toList());
    }




    public StarChangeRecord getLastChangeRecord(UserIdCode idCode,StarLevelEnum starLevel) {

        if (starLevel == StarLevelEnum.NONE) {
            return null;
        }

        List<StarChangeRecord> starChangeRecords =
                starChangeRecordRepository.batchGetLastChangeRecord(List.of(idCode));
        if (starChangeRecords == null || CollectionUtils.isEmpty(starChangeRecords)) {
            throw ApplicationException.error(ApplicationExceptionCode.INVALID_DATA,"未找到签约记录");
        }
        StarChangeRecord starChangeRecord = starChangeRecords.get(0);
        if (!starChangeRecord.getAfterStarLevel().equals(starLevel.getCode())) {
            throw ApplicationException.error(ApplicationExceptionCode.INVALID_DATA,"签约记录与用户等级不匹配");
        }
        return starChangeRecord;
    }
}
